import WebGl from '@/modules/three';
const { Three, TWEEN, dat, Stats } = WebGl;

class WebGlControl {
  private canvas: any;
  private gl: any;
  // private camera:any
  // private scene:any
  // private renderer:any;
  // private animateFrame:any

  public init = () => {
    this.canvas = document.getElementById('WebGL-test');
    this.gl = this.canvas.getContext('webgl');
    console.log('canvas::', this.canvas, this.gl);
    // 确认WebGL支持性
    if (!this.gl) {
      alert('无法初始化WebGL，你的浏览器、操作系统或硬件等可能不支持WebGL。');
      return;
    }

    this.addDot(); //画一个点
    this.addSquare(); //画一个矩形(四边形)
    this.addTriAngle(); //画一个三维的三角形
    this.addCube(); //画一个立方体
  };
  public destroy = () => {
    // this.scene.clear();
    // this.renderer.dispose();
    // this.renderer.forceContextLoss()
    // this.camera = null
    // this.scene = null
    // this.renderer = null
    // cancelAnimationFrame(this.animateFrame)
  };

  private addDot = () => {
    //顶点着色器源码
    let vertexShaderSource =
      '' +
      'void main(){' +
      //给内置变量gl_PointSize赋值像素大小
      '   gl_PointSize=10.0;' +
      //顶点位置，位于坐标原点
      '   gl_Position =vec4(0.0,0.0,0.0,1.0);' +
      '}';
    //片元着色器源码
    let fragShaderSource =
      '' +
      'void main(){' +
      //定义片元颜色
      '   gl_FragColor = vec4(0.0,0.4,1.0,1.0);' +
      '}';

    var program = this.initShader(
      this.gl,
      vertexShaderSource,
      fragShaderSource,
    );
    //开始绘制，显示器显示结果
    this.gl.drawArrays(this.gl.POINTS, 0, 1);
  };

  private addSquare = () => {
    //顶点着色器源码
    let vertexShaderSource =
      '' +
      //attribute声明vec4类型变量apos
      'attribute vec4 apos;' +
      'void main(){' +
      //顶点坐标apos赋值给内置变量gl_Position
      '   gl_Position =apos;' +
      '}';

    //片元着色器源码
    let fragShaderSource =
      '' +
      'void main(){' +
      //定义片元颜色
      '   gl_FragColor = vec4(0.0,0.0,0.0,1.0);' +
      '}';

    var program = this.initShader(
      this.gl,
      vertexShaderSource,
      fragShaderSource,
    );

    //获取顶点着色器的位置变量apos，即aposLocation指向apos变量。
    var aposLocation = this.gl.getAttribLocation(program, 'apos');
    //类型数组构造函数Float32Array创建顶点数组
    var data = new Float32Array([0.2, 0.5, -0.2, 0.5, -0.5, -0.5, 0.5, -0.5]);
    //创建缓冲区对象
    var buffer = this.gl.createBuffer();
    //绑定缓冲区对象
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
    //顶点数组data数据传入缓冲区
    this.gl.bufferData(this.gl.ARRAY_BUFFER, data, this.gl.STATIC_DRAW);
    //缓冲区中的数据按照一定的规律传递给位置变量apos（2：2个数据为一组[x,y]）
    this.gl.vertexAttribPointer(aposLocation, 2, this.gl.FLOAT, false, 0, 0);
    //允许数据传递
    this.gl.enableVertexAttribArray(aposLocation);

    //开始绘制图形
    this.gl.drawArrays(this.gl.LINE_LOOP, 0, 4);
  };

  private addTriAngle = () => {
    //顶点着色器源码
    let vertexShaderSource =
      '' +
      //attribute声明vec4类型变量apos
      'attribute vec4 apos;' +
      'void main(){' +
      //顶点坐标apos赋值给内置变量gl_Position
      // '   gl_Position =apos;' +
      '   gl_Position = vec4(apos.x-0.4,apos.y,apos.z,1);' + //vec4可以直接当成函数调用，
      '}';
    //上面的平移效果也可以这样（利用矩阵运算，平移、缩放等操作）：
    vertexShaderSource =
      '' +
      //attribute声明vec4类型变量apos
      'attribute vec4 apos;' +
      'void main(){' +
      //创建平移矩阵(沿x轴平移-0.4)
      //1   0   0  -0.4
      //0   1   0    0
      //0   0   1    0
      //0   0   0    1
      'mat4 m4 = mat4(1,0,0,0,  0,1,0,0,  0,0,1,0,  -0.4,0,0,1);' +
      //平移矩阵m4左乘顶点坐标(vec4类型数据可以理解为线性代数中的nx1矩阵，即列向量)
      '   gl_Position = m4*apos;' +
      '}';
    //mat4和vec4一样用来声明数据类型，和vec4一样也具有构造数据的功能
    //vec4是4x1矩阵，mat4是4x4矩阵，mat4()函数括号中的16个数据，每四个为一组，以列为准，前四个数就是mat4矩阵的第一列，后面的按顺序依次排列。

    //片元着色器源码
    let fragShaderSource =
      '' +
      'void main(){' +
      //定义片元颜色
      '   gl_FragColor = vec4(0.0,0.0,0.0,1.0);' +
      '}';

    var program = this.initShader(
      this.gl,
      vertexShaderSource,
      fragShaderSource,
    );

    //获取顶点着色器的位置变量apos，即aposLocation指向apos变量。
    var aposLocation = this.gl.getAttribLocation(program, 'apos');
    //9个元素构建三个顶点的xyz坐标值
    var data = new Float32Array([0, 0, 1, 0, 1, 0, 1, 0, 0]);
    // for(var i = 0;i<9;i += 3 )
    // {
    //     data[i] += -0.4;
    // } //平移，每个点的x都-0.4

    //创建缓冲区对象
    var buffer = this.gl.createBuffer();
    //绑定缓冲区对象
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
    //顶点数组data数据传入缓冲区
    this.gl.bufferData(this.gl.ARRAY_BUFFER, data, this.gl.STATIC_DRAW);
    //缓冲区中的数据按照一定的规律传递给位置变量apos（3：3个数据为一组[x,y,z]）
    this.gl.vertexAttribPointer(aposLocation, 3, this.gl.FLOAT, false, 0, 0);
    //允许数据传递
    this.gl.enableVertexAttribArray(aposLocation);

    //开始绘制图形
    this.gl.drawArrays(this.gl.LINE_LOOP, 0, 3);

    /**
     * 看到的是一个直角三角形，实际在三维空间中画的是一个等边三角形。
     * 其实直角所在的顶点是在Z轴上，因为默认是沿Z轴方向观察的，所以看到的是一个投影，就变成了直角三角形
     * **/
  };

  private addCube = () => {
    //顶点着色器源码
    var vertexShaderSource =
      '' +
      //attribute声明vec4类型变量apos
      'attribute vec4 apos;' +
      'void main(){' +
      //设置几何体轴旋转角度为30度，并把角度值转化为浮点值
      'float radian = radians(30.0);' +
      //求解旋转角度余弦值
      'float cos = cos(radian);' +
      //求解旋转角度正弦值
      'float sin = sin(radian);' +
      //引用上面的计算数据，创建绕x轴旋转矩阵
      // 1      0      0    0
      // 0   cosα   sinα    0
      // 0  -sinα   cosα    0
      // 0      0      0    1
      'mat4 mx = mat4(1,0,0,0,  0,cos,-sin,0,  0,sin,cos,0,  0,0,0,1);' +
      //引用上面的计算数据，创建绕y轴旋转矩阵
      // cosβ   0   sinβ    0
      //    0   1      0    0
      //-sinβ   0   cosβ    0
      //    0   0      0    1
      'mat4 my = mat4(cos,0,-sin,0,  0,1,0,0,  sin,0,cos,0,  0,0,0,1);' +
      //两个旋转矩阵、顶点齐次坐标连乘
      '   gl_Position = mx*my*apos;' +
      '}';
    //片元着色器源码
    var fragShaderSource =
      '' + 'void main(){' + '   gl_FragColor = vec4(1.0,0.3,0.3,1.0);' + '}';
    //初始化着色器
    var program = this.initShader(
      this.gl,
      vertexShaderSource,
      fragShaderSource,
    );
    //获取顶点着色器的位置变量apos
    var aposLocation = this.gl.getAttribLocation(program, 'apos');

    //9个元素构建三个顶点的xyz坐标值
    var data = new Float32Array([
      //z为0.5时，xOy平面上的四个点坐标
      0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5,
      //z为-0.5时，xOy平面上的四个点坐标
      0.5, 0.5, -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5,
      //上面两组坐标分别对应起来组成一一对(z轴方向的4条边线)
      0.5, 0.5, 0.5, 0.5, 0.5, -0.5,

      -0.5, 0.5, 0.5, -0.5, 0.5, -0.5,

      -0.5, -0.5, 0.5, -0.5, -0.5, -0.5,

      0.5, -0.5, 0.5, 0.5, -0.5, -0.5,
    ]);

    //创建缓冲区对象
    var buffer = this.gl.createBuffer();
    //绑定缓冲区对象
    this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
    //顶点数组data数据传入缓冲区
    this.gl.bufferData(this.gl.ARRAY_BUFFER, data, this.gl.STATIC_DRAW);
    //缓冲区中的数据按照一定的规律传递给位置变量apos
    this.gl.vertexAttribPointer(aposLocation, 3, this.gl.FLOAT, false, 0, 0);
    //允许数据传递
    this.gl.enableVertexAttribArray(aposLocation);

    //LINE_LOOP模式绘制前四个点
    this.gl.drawArrays(this.gl.LINE_LOOP, 0, 4);
    //LINE_LOOP模式从第五个点开始绘制四个点
    this.gl.drawArrays(this.gl.LINE_LOOP, 4, 4);
    //LINES模式绘制后8个点
    this.gl.drawArrays(this.gl.LINES, 8, 8);
  };

  //初始化着色器方法
  private initShader = (
    gl: any,
    vertexShaderSource: any,
    fragmentShaderSource: any,
  ) => {
    //创建顶点着色器对象
    var vertexShader = gl.createShader(gl.VERTEX_SHADER);
    //创建片元着色器对象
    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    //引入顶点、片元着色器源代码
    gl.shaderSource(vertexShader, vertexShaderSource);
    gl.shaderSource(fragmentShader, fragmentShaderSource);
    //编译顶点、片元着色器
    gl.compileShader(vertexShader);
    gl.compileShader(fragmentShader);

    //创建程序对象program
    var program = gl.createProgram();
    //附着顶点着色器和片元着色器到program
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    //链接program
    gl.linkProgram(program);
    //使用program
    gl.useProgram(program);
    //返回程序program对象
    return program;
  };

  // private animate = () => {

  //   this.render();

  //   this.animateFrame = requestAnimationFrame( this.animate );
  // }
  // private render = () => {

  //   this.renderer.render( this.scene, this.camera );
  // }
}

const webGlControl = new WebGlControl();
export default webGlControl;
